package org.jim.server.command.handler;

import com.im.app.manager.ConversationManager;
import com.im.app.manager.UserManager;
import com.im.app.model.Conversations;
import com.im.app.model.Lixian;
import com.im.app.model.OfflineReply;
import com.im.app.model.User;
import com.im.app.service.*;
import com.im.app.utils.SpringUtils;
import com.im.app.utils.uuid.IdUtils;
import org.jim.core.ImChannelContext;
import org.jim.core.ImPacket;
import org.jim.core.config.ImConfig;
import org.jim.core.exception.ImException;
import org.jim.core.packets.*;
import org.jim.core.utils.JsonKit;
import org.jim.server.ImServerChannelContext;
import org.jim.server.JimServerAPI;
import org.jim.server.command.AbstractCmdHandler;
import org.jim.server.config.ImServerConfig;
import org.jim.server.protocol.ProtocolManager;
import org.jim.server.queue.MsgQueueRunnable;
import org.jim.server.util.ChatKit;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 版本: [1.0]
 * 功能说明: 聊天请求cmd消息命令处理器
 * @author : WChao 创建时间: 2017年9月22日 下午2:58:59
 */
public class ChatReqHandler extends AbstractCmdHandler {

	@Override
	public ImPacket handler(ImPacket packet, ImChannelContext channelContext) throws ImException {
		ImServerChannelContext imServerChannelContext = (ImServerChannelContext)channelContext;
		if (packet.getBody() == null) {
			throw new ImException("body is null");
		}
		ChatBody chatBody = ChatKit.toChatBody(packet.getBody(), channelContext);
		chatBody.setCreateTime(new Date().getTime());
		packet.setBody(chatBody.toByte());
		//聊天数据格式不正确
		if(chatBody == null || chatBody.getChatType() == null){
			ImPacket respChatPacket = ProtocolManager.Packet.dataInCorrect(channelContext);
			return respChatPacket;
		}

		if (UserManager.getManager().isBlack(chatBody.getFrom())){
			RespBody body = new RespBody();
			body.setCommand(Command.COMMAND_ADD_BLACK_RESP);
			body.setData(chatBody.getFrom());
			body.setMsg("您已被拉黑");
			ImPacket chatPacket = new ImPacket(Command.COMMAND_ADD_BLACK_RESP,body.toByte());
			JimServerAPI.sendToUser(chatBody.getFrom(),chatPacket);
			return null;
		}

		IUserService userService = SpringUtils.getBean(IUserService.class);
		User user = userService.getUserByUserId(chatBody.getFrom());
		if (user != null){
			chatBody.setAvatar(user.getAvatar());
			chatBody.setNickName(user.getName());
		}



		chatBody.setCreateTime(new Date().getTime());
		//异步调用业务处理消息接口
		MsgQueueRunnable msgQueueRunnable = getMsgQueueRunnable(imServerChannelContext);
		msgQueueRunnable.addMsg(chatBody);
		msgQueueRunnable.executor.execute(msgQueueRunnable);
		ImPacket chatPacket = new ImPacket(Command.COMMAND_CHAT_REQ,new RespBody(Command.COMMAND_CHAT_REQ,chatBody).toByte());
		//设置同步序列号;
		chatPacket.setSynSeq(packet.getSynSeq());
		ImServerConfig imServerConfig = ImConfig.Global.get();
		boolean isStore = ImServerConfig.ON.equals(imServerConfig.getIsStore());
		//私聊
		if(ChatType.CHAT_TYPE_PRIVATE.getNumber() == chatBody.getChatType()){

			String toId = chatBody.getTo();
			String fromId = chatBody.getFrom();
			//多端登录，发送给其它端
			JimServerAPI.sendToOwner(fromId, chatPacket,channelContext);
			changeSignConversation(chatBody);
			ImPacket imPacket = null;
			if(ChatKit.isOnline(toId, isStore)){
				JimServerAPI.sendToUser(toId, chatPacket);
				//发送成功响应包
				imPacket = ProtocolManager.Packet.success(chatBody, channelContext);
			}else{
				//用户不在线响应包
				imPacket = ProtocolManager.Packet.offline(chatBody,channelContext);
				if (chatBody.getMsgType() != 7){
					//离线回复
					sendOfflineReply(chatBody,imServerChannelContext);
				}
			}
			if (chatBody.getMsgType() == 7){
				sendQuestion(chatBody,imServerChannelContext);
			}
			return imPacket;

		//群聊
		}else if(ChatType.CHAT_TYPE_PUBLIC.getNumber() == chatBody.getChatType()){
			String groupId = chatBody.getGroupId();
			JimServerAPI.sendToGroup(groupId, chatPacket);
			Date date = new Date();
			IGroupMemberService groupMemberService = SpringUtils.getBean(IGroupMemberService.class);
			List<GroupMember> groupMembers = groupMemberService.selectGroupMemberByGroupId(groupId);
			for (GroupMember groupMember : groupMembers){

				org.jim.core.packets.User byUser = JimServerAPI.getByUser(groupMember.getUserId());
				if (byUser != null){
					if (byUser.getType() == 1 && chatBody.getFromType() == 1){
						int count = 1;
						if (groupMember.getUserId().equals(chatBody.getFrom())){
							count = 0;
						}
						updateGroupConversation(chatBody,groupMember.getUserId(),groupId,date,count);
					}
				}
			}
			//发送成功响应包
			return ProtocolManager.Packet.success(chatBody,channelContext);
		}
		return null;
	}

	private void sendQuestion(ChatBody chatBody,ImServerChannelContext imServerChannelContext){
		Lixian lixian = JsonKit.toBean(chatBody.getContent(),Lixian.class);
		if (lixian == null) return;
		String id = IdUtils.simpleUUID().replace("-","");
		String from = chatBody.getTo();
		String to = chatBody.getFrom();
		String content = lixian.getContent();
		int msgType = lixian.getMsgType();
		Long createTime = new Date().getTime();

		IUserService userService = SpringUtils.getBean(IUserService.class);
		User kefUser = userService.getKefuUser(from);

		ChatBody chatBodyLx = ChatBody.newBuilder().setId(id).chatType(2).msgType(msgType).from(from).to(to).content(content).setCreateTime(createTime).build();
		chatBodyLx.setFromType(1);
		chatBodyLx.setNickName(kefUser.getName());
		chatBodyLx.setAvatar(kefUser.getAvatar());
		ImPacket chatPacket = new ImPacket(Command.COMMAND_CHAT_REQ,new RespBody(Command.COMMAND_CHAT_REQ,chatBodyLx).toByte());
		JimServerAPI.sendToUser(from, chatPacket);
		JimServerAPI.sendToUser(to, chatPacket);
		MsgQueueRunnable msgQueueRunnable = getMsgQueueRunnable(imServerChannelContext);
		msgQueueRunnable.addMsg(chatBodyLx);
		msgQueueRunnable.executor.execute(msgQueueRunnable);
	}


	private void sendOfflineReply(ChatBody chatBody,ImServerChannelContext imServerChannelContext){
		String from = chatBody.getTo();
		String to = chatBody.getFrom();
		IOfflineReplyService offlineReplyService = SpringUtils.getBean(IOfflineReplyService.class);
		OfflineReply offlineReply = new OfflineReply();
		offlineReply.setUserId(from);
		List<OfflineReply> offlineReplyList = offlineReplyService.selectOfflineReplyList(offlineReply);
		if (offlineReplyList.size() > 0){
			IUserService userService = SpringUtils.getBean(IUserService.class);
			User kefUser = userService.getKefuUser(from);
			for (OfflineReply reply : offlineReplyList) {
				String id = IdUtils.simpleUUID().replace("-","");
				Long createTime = new Date().getTime();
				ChatBody chatBodyO = ChatBody.newBuilder().setId(id).chatType(2).msgType(reply.getMsgType()).from(from).to(to).content(reply.getContent()).setCreateTime(createTime).build();
				chatBodyO.setNickName(kefUser.getName());
				chatBodyO.setFromType(1);
				chatBodyO.setAvatar(kefUser.getAvatar());
				ImPacket chatPacket = new ImPacket(Command.COMMAND_CHAT_REQ,new RespBody(Command.COMMAND_CHAT_REQ,chatBodyO).toByte());
				JimServerAPI.sendToUser(from, chatPacket);
				JimServerAPI.sendToUser(to, chatPacket);
				MsgQueueRunnable msgQueueRunnable = getMsgQueueRunnable(imServerChannelContext);
				msgQueueRunnable.addMsg(chatBodyO);
				msgQueueRunnable.executor.execute(msgQueueRunnable);
			}
		}

	}


	private void changeSignConversation(ChatBody body){
		Date date = new Date();
		updateUserConversation(body,body.getFrom(),body.getTo(),date,0);
		updateUserConversation(body,body.getTo(),body.getFrom(),date,1);
	}

	private void updateUserConversation(ChatBody chatBody,String userId,String toId,Date date,int unreadCount){
		ConversationsService conversationsService = SpringUtils.getBean(ConversationsService.class);
		Conversations conversation = conversationsService.selectByUser(userId, toId);
		String json = JsonKit.toJSONString(chatBody);
		if(conversation != null){
			conversation.setLastMessage(json);
			conversation.setLastTime(date.getTime());
			conversation.setLastMessageId(chatBody.getId());
			conversation.setUnreadCount(conversation.getUnreadCount() + unreadCount);
			ConversationManager.getManager().sendUserChange(conversation);
			conversationsService.update(conversation);
		}else {
			IUserService userService = SpringUtils.getBean(IUserService.class);
			User user = userService.getUserByUserId(toId);
			if (user != null){
				conversation = ConversationManager.getManager().createConversation(chatBody,userId,user.getName(),user.getAvatar(),unreadCount);
				conversationsService.insert(conversation);
				ConversationManager.getManager().cacheConversation(conversation);
			}
		}
	}

	private void updateGroupConversation(ChatBody chatBody,String userId,String groupId,Date date,Integer count){
		ConversationsService conversationsService = SpringUtils.getBean(ConversationsService.class);
		IGroupService groupService = SpringUtils.getBean(IGroupService.class);
		Conversations conversation = conversationsService.selectByGroup(userId, groupId);
		Group group = groupService.selectGroupsByGroupId(groupId);
		String json = JsonKit.toJSONString(chatBody);
		if(conversation != null){
			conversation.setUnreadCount(conversation.getUnreadCount()+count);
			conversation.setLastMessage(json);
			conversation.setLastTime(date.getTime());
			conversation.setLastMessageId(chatBody.getId());
			ConversationManager.getManager().sendUserChange(conversation);
			conversationsService.update(conversation);
		}else {
			if (group != null){
				conversation = ConversationManager.getManager().createConversation(chatBody,userId,group.getName(),group.getAvatar(),count);
				conversation.setAvatar(group.getAvatar());
				conversation.setNickName(group.getName());
				conversationsService.insert(conversation);
				ConversationManager.getManager().cacheConversation(conversation);
			}
		}
	}


	@Override
	public Command command() {
		return Command.COMMAND_CHAT_REQ;
	}

	/**
	 * 获取聊天业务处理异步消息队列
	 * @param imServerChannelContext IM通道上下文
	 * @return
	 */
	private MsgQueueRunnable getMsgQueueRunnable(ImServerChannelContext imServerChannelContext){
		MsgQueueRunnable msgQueueRunnable = (MsgQueueRunnable)imServerChannelContext.getMsgQue();
		if(Objects.nonNull(msgQueueRunnable.getProtocolCmdProcessor())){
			return msgQueueRunnable;
		}
		synchronized (MsgQueueRunnable.class){
			msgQueueRunnable.setProtocolCmdProcessor(this.getSingleProcessor());
		}
		return msgQueueRunnable;
	}

}
